package cn.remex.contrib.service;

import cn.remex.RemexConstants;
import cn.remex.RemexConstants.UserType;
import cn.remex.contrib.appbeans.DataRvo;
import cn.remex.core.RemexContext;
import cn.remex.core.CoreSvo;
import cn.remex.core.exception.ServiceCode;
import cn.remex.core.util.Assert;
import cn.remex.core.util.MapHelper;
import cn.remex.db.Database;
import cn.remex.db.DbCvo;
import cn.remex.db.DbRvo;
import cn.remex.db.model.SysMenu;
import cn.remex.db.model.SysRole;
import cn.remex.db.model.SysUser;
import cn.remex.db.rsql.RsqlConstants;
import cn.remex.db.rsql.model.ModelableImpl;
import cn.remex.db.sql.Sort;
import cn.remex.db.sql.SqlColumn;
import cn.remex.web.service.BsRvo;
import cn.remex.web.service.BusinessService;
import cn.remex.wechat.WeChat;
import cn.remex.wechat.WeChatService;
import cn.remex.wechat.beans.ticket.QrcodeUrl;
import cn.remex.wechat.models.WeChatNotify;
import cn.remex.wechat.models.WeChatUser;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;

import static cn.remex.core.exception.ServiceCode.WEIXIN_HAS_BIND;
import static cn.remex.core.exception.ServiceCode.WEIXIN_NOT_BIND;
import static cn.remex.core.util.Judgment.nullOrBlank;
import static cn.remex.db.sql.WhereGroupOp.OR;
import static cn.remex.db.sql.WhereRuleOper.equal;
import static cn.remex.db.sql.WhereRuleOper.gt;

/** 
 * @author liuhengyang 
 * date 2016-4-21 下午6:20:59
 * @version 版本号码
 */
@BusinessService
public class UserService {

    @BusinessService
    public BsRvo updateUserStatus(String statusBean) {
        SysUser curUser = RemexContext.obtainCurUser();

        curUser.setStatusBean(statusBean);
        Database.getSession().store(curUser);
        return new BsRvo(ServiceCode.SUCCESS, "OK");
    }

    @BusinessService
    public BsRvo userProfile() {
        String UID = CoreSvo.valCookieValue("UID");
        Assert.notNullAndEmpty(UID, ServiceCode.ACCOUNT_NOT_AUTH, "请先登录!");

        SysUser curUser = Database.createDbCvo(SysUser.class)
                .filterBy(SysUser::getId, equal, UID)
                .withBase(u->{u.getId();u.getHeadimgurl();u.getUsername();u.getUserType();u.getMobile();u.getNickname();u.getSex();u.getStaffNo();u.getEffectFlag();})
                .withList(SysUser::getRoles, l -> l.withList(SysRole::getMenus, menu->menu.withBase().withModel(SysMenu::getSupMenu)).withList(SysRole::getModules, SqlColumn::withBase)).rowCount(1000)
                .ready()
                .queryBean();

        Assert.notNullAndEmpty(curUser, ServiceCode.ACCOUNT_ERROR, "用户信息错误!");

        Map<String, Map<String,Object>> menus = new HashMap<>();
        if (!nullOrBlank(curUser.getRoles()))
            curUser.getRoles().forEach(
                    r -> {
                        if (r.getMenus() != null){
                            r.getMenus().forEach(
                                    m -> {
                                        Map<String, Object> m2 = new HashMap<>();
                                        m2.put("id", m.getId());
                                        m2.put("nodeName", m.getNodeName());
//                                        m2.put("nodeUri", m.getNodeUri());
//                                        m2.put("icon", m.getIcon());
//                                        if (m.getSupMenu() != null) {
//                                            m2.put("supMenu", MapHelper.toMap("id",m.getSupMenu().getId()));
//                                        }
                                        menus.put(m.getId(), m2);
                                    });
                            r.setMenus(null);//节约一点资源
                        }
                    });

        Map profile = new HashMap<>();
        profile.put("menus", menus);
        profile.put("curUser", curUser);


        return new BsRvo(ServiceCode.SUCCESS, "Query UserProfile Finished.", profile);
    }
    @BusinessService(cachedArgIndexs = 0)
    public BsRvo homeMenus(String rootMenu) {
        //获取三层菜单返回给前端
        DbCvo<SysMenu,?> dbCvo = Database.createDbCvo(SysMenu.class)
                .orderBy(SysMenu::getNodeOrder, Sort.ASC)
                .filterByModel(SysMenu::getSupMenu,sup->sup.filterBy(SysMenu::getNodeName, equal, nullOrBlank(rootMenu) ? "ROOTMENU" : rootMenu))
                .withModel(SysMenu::getSupMenu, c -> c.withBase(ModelableImpl::getId))
                .withBase().withList(SysMenu::getSubMenus, sm->sm.withBase().withList(SysMenu::getSubMenus, SqlColumn::withBase))
                .rowCount(1000);
        DbRvo dbRvo = dbCvo.ready().query();
        return new DataRvo(dbRvo);
    }
    @BusinessService(needAuth = false)
    public BsRvo logout(String username, String password, String redirect) {
        RemexContext.clearToken();
//        return new BsRvo(ServiceCode.SUCCESS, "退出登录", null, RemexConstants.ResponseContentType.redirect, "./login.html");
        return new BsRvo(ServiceCode.SUCCESS, "退出登录");
    }
    @BusinessService
    public BsRvo resetPassword(String oldPassword,String newPassword){
        if(nullOrBlank(oldPassword.trim()) || nullOrBlank(newPassword.trim()))
            return new BsRvo(ServiceCode.ACCOUNT_PASSWORD_INVALID, "原密码/新密码不能为空!"); //,"10000"

        SysUser sysUser = RemexContext.obtainCurUser();
       /* if("123".equals(newPassword)){//测试
            return new BsRvo(true, "成功", "0000","1");
        }*/
        if(sysUser.getPassword().equals(oldPassword)){
            sysUser.setPassword(newPassword.trim());
            Database.getSession().store(sysUser);
            RemexContext.clearToken();
            return new BsRvo(ServiceCode.SUCCESS, "成功");
        }else{
            return new BsRvo(ServiceCode.ACCOUNT_PASSWORD_NOTMATCH, "原密码不能正确！");
        }
    }
    @BusinessService
    public BsRvo modifyMobile(String oldPassword, String mobile) {
        Assert.notNullAndEmpty(oldPassword, ServiceCode.ACCOUNT_PASSWORD_INVALID, "密码不能为空!");
        Assert.notNullAndEmpty(mobile, ServiceCode.FAIL, "手机不能为空!");

        SysUser sysUser = RemexContext.obtainCurUser();
       /* if("123".equals(newPassword)){//测试
            return new BsRvo(true, "成功", "0000","1");
        }*/
        if (sysUser.getPassword().equals(oldPassword)) {
            sysUser.setMobile(mobile);
            Database.getSession().store(sysUser);
            return new BsRvo(ServiceCode.SUCCESS, "成功");
        } else {
            return new BsRvo(ServiceCode.ACCOUNT_PASSWORD_NOTMATCH, "原密码不能正确！");
        }
    }
    @BusinessService(needAuth = false)
    public BsRvo login(String username, String password,String redirect) {
        Assert.notNullAndEmpty(username, ServiceCode.ACCOUNT_USERNAME_INVALID,"用户名不能为空！");
        Assert.notNullAndEmpty(password, ServiceCode.ACCOUNT_PASSWORD_INVALID,"登录密码不能为空！");

        List<SysUser> sysUsers = Database.createDbCvo(SysUser.class)
                .withList(SysUser::getRoles, r->r.withList(SysRole::getModules, SqlColumn::withBase))
                .withBase()
                .filterBy(SysUser::getPassword, equal, password)
                .filterByGroup(g -> g
                        .filterOper(OR)
                        .filterBy(SysUser::getUsername, equal, username)
                        .filterBy(SysUser::getMobile, equal, username))
                .ready().query().obtainObjects(SysUser.class);


        if(sysUsers.size()==1) {
            Map tokeMap = RemexContext.placeToken(sysUsers.get(0));
            ArrayList modules = new ArrayList();
            if ( sysUsers.get(0).getRoles()!=null){ // TODO 普通用户添加权限
                sysUsers.get(0).getRoles().forEach(role->{
                    if(role.getModules()!=null)
                        role.getModules().forEach(moduel->modules.add(moduel));
                });
            }
            return new BsRvo(ServiceCode.SUCCESS, "登录成功", MapHelper.toMap(tokeMap, "statusBean", sysUsers.get(0).getStatusBean(), "modules" ,modules ));
        }else if (sysUsers.size() > 1) {
            RemexContext.clearToken();
            return new BsRvo(ServiceCode.ACCOUNT_ERROR, "账号异常");
        }else {
            RemexContext.clearToken();
            return new BsRvo(ServiceCode.FAIL, "用户名/密码错误");
        }
    }

    @BusinessService(needAuth = false)
    public BsRvo obtainWeixinLoginUrl(String appid,String agentid){
        QrcodeUrl qrcodeUrl = new QrcodeUrl(WeChat.getWeChatApp(appid,agentid).qrcode_create_scene(WeChatService.weixinLoginQrcodeUrl_SceneId, "120"));
        Assert.notNullAndEmpty(qrcodeUrl.getTicketUrl(), ServiceCode.FAIL,"通过微信登录时，获取微信二维码失败");
        return new BsRvo(ServiceCode.SUCCESS, "以获取到绑定微信的二维码", qrcodeUrl);
    }
    @BusinessService(needAuth = false)
    public BsRvo loginByWeixin(String ticket) {
        Assert.notNullAndEmpty(ticket, ServiceCode.FAIL, "Ticket不能为空！");
	    WeChatNotify weChatNotify = Database.createDbCvo(WeChatNotify.class)
			    .filterBy(WeChatNotify::getTicket, equal, ticket)
			    .filterBy(WeChatNotify::getMsgTime, gt, new Date().getTime()/1000-3*60)//有效期，ticket
	            .ready().queryBean();

        if(nullOrBlank(weChatNotify)){
	        return new BsRvo(ServiceCode.FAIL,"未扫描二维码");
        }else if(new Date().getTime()/1000 - weChatNotify.getMsgTime()> 5*60){//五分钟内有效
            return new BsRvo(ServiceCode.FAIL,"扫描超时");
        }

        WeChatUser curWeChatUser = Database.select(WeChatUser.class)
			    .filterBy(WeChatUser::getOpenid, equal, weChatNotify.getFromUserName())
                .withBase(WeChatUser::getId)
                .withModel(WeChatUser::getSysUser)
			    .ready().queryBean();

		if(nullOrBlank(curWeChatUser) || nullOrBlank(curWeChatUser.getSysUser())){
			return new BsRvo(ServiceCode.FAIL, "请使用绑定的微信号扫描二维码");
		}else{
			RemexContext.placeToken(curWeChatUser.getSysUser());
			return new BsRvo(ServiceCode.SUCCESS, "登录成功", "/");
		}

    }
    @BusinessService
    public BsRvo bindWeixin(String appid, String agentid){
        WeChatUser curWeChatUser = Database.select(WeChatUser.class)
                .filterBy(WeChatUser::getSysUser, equal, RemexContext.obtainCurUser())
                .withBase(WeChatUser::getId)
                .withModel(WeChatUser::getSysUser)
                .ready().queryBean();

        Assert.nullOrEmpty(curWeChatUser, WEIXIN_HAS_BIND,"已经绑定");
        QrcodeUrl aa = new QrcodeUrl(WeChat.getWeChatApp(appid,agentid).qrcode_create_limitScene(RemexContext.obtainCurUser().getId()));
        Assert.notNullAndEmpty(aa.getTicketUrl(), ServiceCode.FAIL,"绑定微信时，获取微信二维码失败");
        return new BsRvo(ServiceCode.SUCCESS, "以获取到绑定微信的二维码",aa);
    }
    @BusinessService
    public BsRvo checkBindWeixin(String ticket,String createTime){

        Assert.notNullAndEmpty(ticket, ServiceCode.FAIL, "Ticket不能为空！");
        WeChatNotify weChatNotify = Database.createDbCvo(WeChatNotify.class)
                .filterBy(WeChatNotify::getTicket, equal, ticket)
                .filterBy(WeChatNotify::getMsgTime, gt, Long.parseLong(createTime)/1000)
                .ready().queryBean();//查找5分钟内是否扫码

        if(nullOrBlank(weChatNotify)){
            return new BsRvo(WEIXIN_NOT_BIND,"未扫描二维码");
        }/*else if(new Date().getTime()/1000 - weChatNotify.getMsgTime()> 5*60){//五分钟内有效
            return new BsRvo(ServiceCode.FAIL,"扫描超时");
        }*/

	    //走到这里说明，已经扫描
	    RemexConstants.logger.info("检查用户状态, openId:" + weChatNotify.getFromUserName());
        WeChatUser curWeChatUser = Database.select(WeChatUser.class)
                .filterBy(WeChatUser::getOpenid, equal, weChatNotify.getFromUserName())
                .withBase(WeChatUser::getId).withModel(WeChatUser::getSysUser)
                .ready().queryBean();

        if (null == curWeChatUser) {
		    return new BsRvo(ServiceCode.OPENID_INVALID, "扫描的微信号无效");
        } else if (null != curWeChatUser.getSysUser()) {
            return new BsRvo(WEIXIN_HAS_BIND, "微信已绑定");
        } else if( null!=curWeChatUser.getSysUser() && !curWeChatUser.getSysUser().getId().equals(RemexContext.obtainCurUser().getId())){
            return new BsRvo(ServiceCode.OPENID_INVALID, "已经绑定其他账号");
        }else {
            return new BsRvo(WEIXIN_NOT_BIND, "微信未绑定");
        }

//        SysUser authUser1 = Database.createDbCvo(SysUser.class).filterById( RemexContext.obtainCurUser().getId()).ready().queryBean();
//        RemexConstants.logger.info("CHECK USER BIND WEIXIN Status, id:" + RemexContext.obtainCurUser().getId());
//        if(authUser1!=null && !Judgment.nullOrBlank(authUser1.getOpenid())){
//            return new BsRvo(ServiceCode.WEIXIN_HAS_BIND,"微信已绑定");
//        }else{
//            return new BsRvo(ServiceCode.WEIXIN_NOT_BIND,"微信未绑定");
//        }
    }
    @BusinessService
    public BsRvo unbindWeixin(String password){
        Assert.notNullAndEmpty(password, ServiceCode.FAIL,"密码不能为空");

        RemexContext.refreshCurUser();//更新缓存
        SysUser loginUser = RemexContext.obtainCurUser();
        if(password.equals(loginUser.getPassword())){
            WeChatUser curWeChatUser = Database.select(WeChatUser.class)
                    .filterBy(WeChatUser::getSysUser, equal, loginUser)
                    .withBase(WeChatUser::getId)
                    .ready().queryBean();

            WeChatService.dismissedBindUser(curWeChatUser.getOpenid());
            RemexContext.refreshCurUser();//更新缓存
            return new BsRvo(ServiceCode.SUCCESS, "解除绑定成功","");
        }else{
            return new BsRvo(ServiceCode.ACCOUNT_PASSWORD_NOTMATCH, "原密码不能正确！");
        }
    }

    //根据用户名注册并登陆一个用户，且默认从cookie中自动绑定更新微信
    public static LoginApiBean loginAndStoreByUsername(UserType type, String username, Function<SysUser, SysUser> createUserFunction, Consumer<SysUser> successConsumer) {
        //根据cookie中的openid更新用户微信信息
        String openid = CoreSvo.valCookieValue("openId");// TODO 此处应该用SHA对openid和username做签名
        return loginAndStoreByUsername(type, username)
                .assignOpenid(openid)
                .onCreateUser(createUserFunction)
                .onLoginSuccess(successConsumer)
                .execute();
//        , beforeUserCreateFunction, successConsumer, assignOpenid
    }

    /**
     * <p>根据username 检查是否存在改用户
     * <p>如果不存在就创建一个
     * <p>本api会根据 needBindOpenid 来更新用户的微信信息
     *
//     * @param type 用户类型 {@link UserType}
//     * @param beforeUserCreateFunction 不为空是创建用户
//     * @param username 用户名
//     * @param successConsumer  登录并创建(更新)成功时用来更新用户信息的 consumer
//     * @param needBindOpenid 待绑定更新的微信openid
//     *                         @return 返回登陆成功信息
     */
//    public static LoginApiBean loginAndStoreByUsername(UserType type, String username
//            , Function<SysUser, SysUser> beforeUserCreateFunction, Consumer<SysUser> successConsumer
//            , String needBindOpenid) {
//        Assert.notNullAndEmpty(type,ServiceCode.FAIL,"通用登录API，必须指定登录类型");
//        Assert.notNullAndEmpty(username,ServiceCode.FAIL,"通用登录API，必须指定登录用户名");
//        DbRvo<SysUser> authUserRvo = Database.createDbCvo(SysUser.class)
//                .filterBy(SysUser::getUserType, equal, type)
//                .filterBy(SysUser::getUsername,equal,username).ready().query();
//        Assert.isTrue(authUserRvo.getRecordCount()<=1,ServiceCode.FAIL,"数据错误用户名存在多个，请联系管理员");
//        SysUser sysUser;
//        boolean hasBindWeiXin =false;
//        if(authUserRvo.getRecordCount()==1){
//            sysUser = authUserRvo.obtainBean();
//        } else if (null != beforeUserCreateFunction && authUserRvo.getRecordCount()==0) {
//            sysUser = new SysUser();
//            sysUser.setUsername(username);
//            sysUser.setUserType(type);
//            sysUser = beforeUserCreateFunction.apply(sysUser);
//            Database.insert(SysUser.class).assignBean(sysUser).execute().assertTrue(rvo -> rvo.getEffectRowCount() == 1, ServiceCode.FAIL, "创建用户失败");
//        } else {
//            return new LoginApiBean(false, false, "登录失败",null);
//        }
//
//        //if(!nullOrBlank(sysUser.getOpenid()) && !nullOrBlank(assignOpenid))RemexConstants.logger.warn("用户微信openid与用户信息中不符，应该是从不同公众号登录进来，curOpenid="+assignOpenid+";sysUser.assignOpenid="+sysUser.getOpenid());
//        //根据 needBindOpenid 更新用户微信信息
//        if (!nullOrBlank(needBindOpenid)) { //needBindOpenid不为空时
//            Assert.isTrue(nullOrBlank(sysUser.getOpenid()), ServiceCode.WEIXIN_CANNOT_BIND, "该账号已被其他微信绑定，登录失败！");
//            hasBindWeiXin =  WeiXinService.bindUser(needBindOpenid, sysUser);
//        }
//
//        //回调相关信息
//        if(null!=successConsumer)successConsumer.accept(sysUser);
//
//        //有修改就保存
//        if(sysUser._getModifyFileds() !=null || RsqlConstants.DS_beanNew.equals(sysUser._getDataStatus())){
//            Database.getSession().store(sysUser);
//        }
//
//        //存放身份验证信息
//        RemexContext.placeToken(sysUser);
//        return new LoginApiBean(true, hasBindWeiXin, "登录成功", RemexContext.placeToken(sysUser));
//    }
    public static LoginApiBean loginAndStoreByUsername(UserType type, String username) {
        Assert.notNullAndEmpty(type,ServiceCode.FAIL,"通用登录API，必须指定登录类型");
        Assert.notNullAndEmpty(username,ServiceCode.FAIL,"通用登录API，必须指定登录用户名");
        RemexContext.clearToken();
        return new LoginApiBean(type, username);
    }

    public static class LoginApiBean {
        private String username;
        private UserType type;
        private boolean status;
        private boolean weixinBinded;
        private String msg;
        private String openid;
        private Map params;
        private Function<SysUser, SysUser> beforeUserCreateFunction;
        private Consumer<SysUser> userCreatedConsumer;
        private Consumer<SysUser> successConsumer;
        private String wechatAppName;

        public LoginApiBean(UserType type, String username) {
            this.type = type;
            this.username = username;
        }

        public LoginApiBean assignOpenid(String openid) {
            this.openid = openid;
            return this;
        }
        public LoginApiBean assignAppName(String wechatAppName) {
            this.wechatAppName = wechatAppName;
            return this;
        }
        public LoginApiBean onCreateUser(Function<SysUser, SysUser> createUserFunction) {
            this.beforeUserCreateFunction = createUserFunction;
            return this;
        }
        public LoginApiBean onCreateUser(Consumer<SysUser> userCreatedConsumer) {
            this.userCreatedConsumer = userCreatedConsumer;
            return this;
        }
        public LoginApiBean onLoginSuccess(Consumer<SysUser> successConsumer) {
            this.successConsumer = successConsumer;
            return this;
        }
        public LoginApiBean execute(){
            Assert.notNullAndEmpty(this.type,ServiceCode.FAIL,"通用登录API，必须指定登录类型");
            Assert.notNullAndEmpty(this.username,ServiceCode.FAIL,"通用登录API，必须指定登录用户名");
            DbRvo<SysUser> authUserRvo = Database.select(SysUser.class)
                    .filterBy(SysUser::getUserType, equal, this.type)
                    .filterBy(SysUser::getUsername,equal,this.username).execute();
            Assert.isTrue(authUserRvo.getRecordCount()<=1,ServiceCode.FAIL,"数据错误用户名存在多个，请联系管理员");
            SysUser sysUser;
            if(authUserRvo.getRecordCount()==1){
                sysUser = authUserRvo.obtainBean();
            } else if (authUserRvo.getRecordCount()==0) {
                sysUser = new SysUser();
                sysUser.setUsername(username);
                sysUser.setUserType(type);
	            if (null != beforeUserCreateFunction) {sysUser = beforeUserCreateFunction.apply(sysUser);}

	            Database.insert(SysUser.class).assignBean(sysUser).execute().assertTrue(rvo -> rvo.getEffectRowCount() == 1, ServiceCode.FAIL, "创建用户失败");
                if(null != userCreatedConsumer){ userCreatedConsumer.accept(sysUser);}

            } else {
                return new LoginApiBean(false, false, "登录失败",null);
            }

        //if(!nullOrBlank(sysUser.getOpenid()) && !nullOrBlank(openid))RemexConstants.logger.warn("用户微信openid与用户信息中不符，应该是从不同公众号登录进来，curOpenid="+openid+";sysUser.openid="+sysUser.getOpenid());
        //根据 needBindOpenid 更新用户微信信息
            if (!nullOrBlank(this.openid)) { //needBindOpenid不为空时
//                Assert.isTrue(nullOrBlank(sysUser.getOpenid()) ||this.openid.equals(sysUser.getOpenid()), ServiceCode.WEIXIN_CANNOT_BIND, "该账号已被其他微信绑定，登录失败！");
                this.status =  WeChatService.bindUser(this.wechatAppName,null, this.openid, sysUser); //TODO 微信有些地方需要appid&agentid来获取app,有时候需要appName(业务逻辑中)获取app,这些功能没有开发完.
            }


            //有修改就保存
            if(sysUser._getModifyFileds() !=null || RsqlConstants.DS_beanNew.equals(sysUser._getDataStatus())){
                Database.getSession().store(sysUser);
            }
            //回调相关信息
            if(null!=successConsumer)successConsumer.accept(sysUser);


            //存放身份验证信息
            this.params = RemexContext.placeToken(sysUser);
            status = true;
            return this;
        }



        public LoginApiBean(boolean status, boolean weixinBinded, String msg, Map<String,?> params) {
            this.status = status;
            this.weixinBinded = weixinBinded;
            this.msg = msg;
            this.params = params;
        }

        public BsRvo toCommLoginBsRvo() {
            return new BsRvo(this.isStatus() ? ServiceCode.SUCCESS : ServiceCode.FAIL, this.getMsg());
        }

        public BsRvo toWeixinEnterLoginBsRvo(Object ... keyAndValue) {
            Assert.isTrue(keyAndValue!=null && keyAndValue.length%2==0,ServiceCode.ERROR,"toWeixinBsRvo功能的参数必须为key-value成对出现");
            if(params==null) params = new HashMap<>();
            params.put("weixinBindStatus", nullOrBlank(this.openid) ? "NOT_BINDED" : "HAS_BINDED");
            if(keyAndValue!=null)
            for(int i=0,c=keyAndValue.length/2;i<c;i++,i++){
                params.put(keyAndValue[i].toString(),keyAndValue[i+1]);
            }

            return new BsRvo(this.isStatus() ? ServiceCode.SUCCESS : ServiceCode.FAIL, this.getMsg(), params);
        }


        public boolean isStatus() {
            return status;
        }

        public void setStatus(boolean status) {
            this.status = status;
        }

        public boolean isWeixinBinded() {
            return weixinBinded;
        }

        public void setWeixinBinded(boolean weixinBinded) {
            this.weixinBinded = weixinBinded;
        }

        public String getMsg() {
            return msg;
        }

        public void setMsg(String msg) {
            this.msg = msg;
        }
    }


}
